﻿#include "SoundRecorder.h"
#include <QDir>
#include <QMediaDevices>
#include "Debug.h"
#include "Model/Data.h"
#include "Toast.h"

using namespace model;
///////////////////////////////////////////
/// 声音录制类
///////////////////////////////////////////
SoundRecorder* SoundRecorder::instance = nullptr;

SoundRecorder* SoundRecorder::get_instance()
{
    if (instance == nullptr) {
        instance = new SoundRecorder();
    }
    return instance;
}

SoundRecorder::SoundRecorder(QObject* parent)
    : QObject(parent), m_isPlaying(false)
{
    // 1. 创建目录
    QDir soundRootPath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
    soundRootPath.mkdir("sound");

    // 2. 初始化录制模块
    QString sound_file_path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/sound";
    QDir    app_data_dir(sound_file_path);
    if (!app_data_dir.exists()) {
        bool res = app_data_dir.mkpath(sound_file_path);
        if (res == false) {
            LOG() << "Failed to create sound file path directory: " << sound_file_path;
            return;
        }
    }

    soundFile.setFileName(RECORD_PATH);

    // 获取默认音频输入设备
    QAudioDevice inputDevice = QMediaDevices::defaultAudioInput();

    // 定义录制格式 - 使用设备首选格式
    QAudioFormat inputFormat = inputDevice.preferredFormat();
    LOG() << "录制设备首选格式 - 采样率:" << inputFormat.sampleRate()
          << ", 通道数:" << inputFormat.channelCount()
          << ", 采样格式:" << inputFormat.sampleFormat();

    audioSource = new QAudioSource(inputDevice, inputFormat, this);

    // 初始化播放模块 - 使用与录制相同的格式
    outputDevice              = QMediaDevices::defaultAudioOutput();
    QAudioFormat outputFormat = inputFormat;  // 使用与录制相同的格式

    // 检查输出设备是否支持这个格式
    if (!outputDevice.isFormatSupported(outputFormat)) {
        LOG() << "播放设备不支持录制格式，使用设备首选格式.";
        outputFormat = outputDevice.preferredFormat();
        LOG() << "播放设备首选格式 - 采样率:" << outputFormat.sampleRate()
              << ", 通道数:" << outputFormat.channelCount()
              << ", 采样格式:" << outputFormat.sampleFormat();
    }

    audioSink = new QAudioSink(outputDevice, outputFormat);
    connect(audioSink, &QAudioSink::stateChanged, this, [=](QAudio::State state) {
        if (state == QAudio::IdleState) {
            LOG() << "IdleState";
            m_isPlaying = false;
            this->stop_play();
            emit this->sound_play_done();
        } else if (state == QAudio::ActiveState) {
            LOG() << "ActiveState";
            m_isPlaying = true;
        } else if (state == QAudio::StoppedState) {
            LOG() << "StoppedState";
            m_isPlaying = false;
            if (audioSink->error() != QAudio::NoError) {
                LOG() << audioSink->error();
            }
        } else if (state == QAudio::SuspendedState) {
            LOG() << "SuspendedState";
            m_isPlaying = false;
        }
    });
}

/// @brief 音频格式转换函数
QByteArray SoundRecorder::convert_audio_format(const QByteArray& inputData, const QAudioFormat& inputFormat, const QAudioFormat& outputFormat)
{
    QByteArray outputData;

    // 获取样本大小
    int inputSampleSize  = inputFormat.bytesPerSample();
    int outputSampleSize = outputFormat.bytesPerSample();

    // 获取通道数
    int inputChannels  = inputFormat.channelCount();
    int outputChannels = outputFormat.channelCount();

    // 计算样本数量
    int sampleCount = inputData.size() / (inputSampleSize * inputChannels);

    // 调整输出数据大小
    outputData.resize(sampleCount * outputSampleSize * outputChannels);

    // 转换逻辑
    if (inputFormat.sampleFormat() == QAudioFormat::Float &&
        outputFormat.sampleFormat() == QAudioFormat::Float) {
        // Float到Float转换
        const float* inputSamples  = reinterpret_cast<const float*>(inputData.constData());
        float*       outputSamples = reinterpret_cast<float*>(outputData.data());

        for (int i = 0; i < sampleCount; ++i) {
            float sampleValue = inputSamples[i * inputChannels];  // 取第一个通道的值

            for (int c = 0; c < outputChannels; ++c) {
                outputSamples[i * outputChannels + c] = sampleValue;
            }
        }
    } else {
        // 其他格式转换（简化处理，实际可能需要更复杂的转换）
        LOG() << "不支持的格式转换";
        return inputData;
    }

    return outputData;
}

void SoundRecorder::start_record()
{
    soundFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
    if (!soundFile.isOpen()) {
        LOG() << "录制文件未打开!";
        return;
    }
    audioSource->start(&soundFile);
}

void SoundRecorder::stop_record()
{
    if (!soundFile.isOpen()) {
        LOG() << "录制文件未打开!";
        return;
    }
    audioSource->stop();
    soundFile.close();
    emit this->sound_record_done(RECORD_PATH);
}

void SoundRecorder::start_play(const QByteArray& content)
{
    if (content.isEmpty()) {
        Toast::showMessage("数据加载中, 请稍后播放");
        return;
    }

    // 获取录制和播放格式
    QAudioFormat recordFormat = audioSource->format();
    QAudioFormat playFormat   = audioSink->format();

    QByteArray playData       = content;

    // 如果录制和播放格式不同，进行转换
    if (recordFormat.channelCount() != playFormat.channelCount() ||
        recordFormat.sampleFormat() != playFormat.sampleFormat()) {
        LOG() << "录制和播放格式不同，进行转换";
        playData = convert_audio_format(content, recordFormat, playFormat);
    }

    // 1. 把数据写入到临时文件
    write_file(PLAY_PATH, playData);

    // 2. 播放语音
    inputFile.setFileName(PLAY_PATH);
    inputFile.open(QIODevice::ReadOnly);
    audioSink->start(&inputFile);
}

void SoundRecorder::stop_play()
{
    audioSink->stop();
    inputFile.close();
}

bool SoundRecorder::is_playing()
{
    return m_isPlaying;
}
